package com.zz.bid.web.controller;

import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import com.github.pagehelper.PageInfo;
import com.zz.bid.annotation.RequiredAccess;
import com.zz.bid.exception.LoginTimeoutException;
import com.zz.bid.exception.base.BidException;
import com.zz.bid.pojo.entity.SettleFlowEnum;
import com.zz.bid.pojo.query.SettleQuery;
import com.zz.bid.pojo.to.ResponseWrapper;
import com.zz.bid.pojo.to.SettleFlowDetails;
import com.zz.bid.pojo.to.SettlementDesc;
import com.zz.bid.pojo.to.UserTO;
import com.zz.bid.service.SettleFlowService;
import com.zz.bid.service.SettleService;
import com.zz.bid.service.UserService;
import com.zz.bid.web.controller.base.BaseController;

import lombok.extern.slf4j.Slf4j;

/**
 * @author chenkehan created at 2020/5/25 10:12 下午
 */
@RestController
@Slf4j
public class SettleController extends BaseController {

    @Autowired
    private SettleService settleService;

    @Autowired
    private UserService userService;

    @Autowired
    private SettleFlowService settleFlowService;

    @PostMapping("/createSettle")
    @Transactional
    public ResponseWrapper create(@RequestBody SettlementDesc settlementDesc) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            settlementDesc.setLastUpdateTime(sdf.format(new Date()));
            settlementDesc.setLastUpdateUser(getUserTO().getAccountName());
            settlementDesc.setCreatedBy(getUserTO().getUserId());
            settlementDesc.setCreatedDate(LocalDateTime.now());
            settleService.create(settlementDesc);
            // 将相应的流程也一并添加
            settleFlowService.addFlows(settlementDesc.getId(), getUserTO().getAccountName());
            return ResponseWrapper.builder().status(HttpStatus.OK.value()).path(request.getServletPath()).data(true)
                .build();
        } catch (Exception e) {
            log.error(e.getMessage());
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return ResponseWrapper.builder().status(HttpStatus.INTERNAL_SERVER_ERROR.value()).data(false)
                .path(request.getServletPath()).message(e.getMessage()).build();
        }
    }

    @PostMapping("/getSettles")
    public ResponseWrapper getSettles(@RequestBody SettleQuery settleQuery) {
        try {
            PageInfo<SettlementDesc> data = settleService.getSettles(settleQuery);
            // 将相应的流程也一并添加
            return ResponseWrapper.builder().status(HttpStatus.OK.value()).path(request.getServletPath()).data(data)
                .build();
        } catch (Exception e) {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return ResponseWrapper.builder().status(HttpStatus.INTERNAL_SERVER_ERROR.value()).data(false)
                .path(request.getServletPath()).message(e.getMessage()).build();
        }
    }

    @GetMapping("settleExport")
    public void export() {
        // excel文件名
        String fileName = "结算信息表" + System.currentTimeMillis() + ".xls";
        SettleQuery settleQuery = new SettleQuery();
        HSSFWorkbook wb = settleService.export(settleQuery);
        // 响应到客户端
        try {
            this.setResponseHeader(response, fileName);
            OutputStream os = response.getOutputStream();
            wb.write(os);
            os.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @PostMapping("/updateSettle")
    @RequiredAccess(109)
    public ResponseWrapper update(@RequestBody SettlementDesc settlementDesc) {
        try {
            settleService.update(settlementDesc);
            return ResponseWrapper.builder().path(request.getServletPath()).data(true).status(HttpStatus.OK.value())
                .build();
        } catch (Exception e) {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return ResponseWrapper.builder().status(HttpStatus.INTERNAL_SERVER_ERROR.value()).message(e.getMessage())
                .path(request.getContextPath()).data(false).build();
        }
    }

    @GetMapping("/doDownloadSettleFile")
    public void doDownloadFile(@RequestParam String fileName, @RequestParam int settleId, @RequestParam int flowId) {
        try {
            byte[] bs = settleService.loadfile(fileName, settleId, flowId);
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition",
                "attachment;filename=\"" + URLEncoder.encode(fileName, "UTF-8") + "\"");
            response.addHeader("Content-Length", String.valueOf(bs.length));
            OutputStream respOut = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            respOut.write(bs);
            respOut.flush();
            respOut.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @PostMapping("/uploadSettleFile")
    @RequiredAccess(103)
    @Transactional
    public ResponseWrapper uploadBidFile(int settleId, int flowId, MultipartFile file) {
        try {
            UserTO userTO = getUserTO();
            settleService.storeFile(settleId, flowId, userTO.getAccountName(), file);
            return ResponseWrapper.builder().path(request.getServletPath()).data(true).status(HttpStatus.OK.value())
                .build();
        } catch (Exception e) {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return ResponseWrapper.builder().status(HttpStatus.INTERNAL_SERVER_ERROR.value()).message(e.getMessage())
                .path(request.getContextPath()).build();
        }
    }

    private UserTO getUserTO() throws LoginTimeoutException {
        String encodedToken = request.getHeader("token");
        if (StringUtils.isEmpty(encodedToken)) {
            log.error("token is null.");
            throw new LoginTimeoutException();
        }
        return userService.getUserInfo(encodedToken);
    }

    @GetMapping("/getSettleFileName")
    public ResponseWrapper getSettleFileName(@RequestParam Integer settleId) {
        try {
            SettleFlowDetails flow = settleService.getFlow(settleId, SettleFlowEnum.AGGREEMENT.getId());
            return ResponseWrapper.builder().path(request.getServletPath()).data(flow).status(HttpStatus.OK.value())
                .build();
        } catch (Exception e) {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return ResponseWrapper.builder().status(HttpStatus.INTERNAL_SERVER_ERROR.value()).message(e.getMessage())
                .path(request.getContextPath()).build();
        }
    }

    @PostMapping("/deleteSettleFile")
    public ResponseWrapper deleteBidFile(@RequestParam Integer settleId, @RequestParam Integer flowId,
        @RequestParam String fileName) {
        try {
            settleService.deleteSettleFile(settleId, flowId, fileName, getUserTO().getAccountName());
            return ResponseWrapper.builder().path(request.getServletPath()).data(true).status(HttpStatus.OK.value())
                .build();
        } catch (Exception e) {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return ResponseWrapper.builder().status(HttpStatus.INTERNAL_SERVER_ERROR.value()).message(e.getMessage())
                .path(request.getContextPath()).build();
        }
    }

    @PostMapping("/deleteSettle")
    public ResponseWrapper deleteSettle(@RequestParam Integer settleId) {
        try {
            settleService.delete(settleId);
            return ResponseWrapper.builder().path(request.getServletPath()).data(true).status(HttpStatus.OK.value())
                .build();
        } catch (BidException e) {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return ResponseWrapper.builder().status(HttpStatus.INTERNAL_SERVER_ERROR.value()).message(e.getMessage())
                .path(request.getContextPath()).build();
        }
    }

    @PostMapping("/updateForTechMan")
    public ResponseWrapper updateForTechMan(@RequestBody SettlementDesc settle) {
        try {
            settleService.updateForTechMan(settle);
            return ResponseWrapper.builder().path(request.getServletPath()).data(true).status(HttpStatus.OK.value())
                .build();
        } catch (Exception e) {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return ResponseWrapper.builder().status(HttpStatus.INTERNAL_SERVER_ERROR.value()).message(e.getMessage())
                .path(request.getContextPath()).build();
        }
    }

    @GetMapping("/getSettleFilesForTechMan")
    public ResponseWrapper getSettleFilesForTechMan(@RequestParam Integer settleId) {
        try {
            List<String> firstReports =
                settleService.getFlow(settleId, SettleFlowEnum.FIRST_REPORTS.getId()).getFileNames();
            List<String> detailReports =
                settleService.getFlow(settleId, SettleFlowEnum.DETAIL_REPORTS.getId()).getFileNames();
            List<String> picAudits = settleService.getFlow(settleId, SettleFlowEnum.PIC_AUDIT.getId()).getFileNames();
            List<String> signSheet = settleService.getFlow(settleId, SettleFlowEnum.SIGN_SHEET.getId()).getFileNames();
            List<String> badworkSignSheet =
                settleService.getFlow(settleId, SettleFlowEnum.BADJOB_SIGN_SHEET.getId()).getFileNames();
            List<String> otherSignSheet =
                settleService.getFlow(settleId, SettleFlowEnum.OTHER_SIGN_SHEET.getId()).getFileNames();
            List<String> witnessSheet =
                settleService.getFlow(settleId, SettleFlowEnum.WITNESS_FILE.getId()).getFileNames();
            List<String> otherSheet = settleService.getFlow(settleId, SettleFlowEnum.OTHER_FILE.getId()).getFileNames();
            List<String> workDifferentFile =
                settleService.getFlow(settleId, SettleFlowEnum.WORK_DIFFERENT_FILE.getId()).getFileNames();

            Map<String, List<String>> resultMap = new HashMap<>();
            resultMap.put("firstReports", firstReports);
            resultMap.put("detailReports", detailReports);
            resultMap.put("picAudits", picAudits);
            resultMap.put("signSheets", signSheet);
            resultMap.put("badWorkSignSheets", badworkSignSheet);
            resultMap.put("otherSignSheets", otherSignSheet);
            resultMap.put("witnessSheets", witnessSheet);
            resultMap.put("otherSheets", otherSheet);
            resultMap.put("workDifferentFiles", workDifferentFile);
            return ResponseWrapper.builder().path(request.getServletPath()).data(resultMap)
                .status(HttpStatus.OK.value()).build();
        } catch (Exception e) {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return ResponseWrapper.builder().status(HttpStatus.INTERNAL_SERVER_ERROR.value()).message(e.getMessage())
                .path(request.getContextPath()).build();
        }
    }

    @PostMapping("/updateForCostMan")
    public ResponseWrapper updateForCostMan(@RequestBody SettlementDesc settle) {
        try {
            settleService.updateForCostMan(settle);
            return ResponseWrapper.builder().path(request.getServletPath()).data(true).status(HttpStatus.OK.value())
                .build();
        } catch (Exception e) {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return ResponseWrapper.builder().status(HttpStatus.INTERNAL_SERVER_ERROR.value()).message(e.getMessage())
                .path(request.getContextPath()).build();
        }
    }

    @GetMapping("/getSettleFilesForCostMan")
    public ResponseWrapper getSettleFilesForCostMan(@RequestParam Integer settleId) {
        try {
            List<String> firstBills = settleService.getFlow(settleId, SettleFlowEnum.FIRST_BILL.getId()).getFileNames();
            List<String> secondBills =
                settleService.getFlow(settleId, SettleFlowEnum.SECOND_BILL.getId()).getFileNames();
            List<String> thirdBills = settleService.getFlow(settleId, SettleFlowEnum.THIRD_BILL.getId()).getFileNames();
            List<String> depositMaterials =
                settleService.getFlow(settleId, SettleFlowEnum.DEPOSIT_MATERIAL.getId()).getFileNames();

            Map<String, List<String>> resultMap = new HashMap<>();
            resultMap.put("firstBills", firstBills);
            resultMap.put("secondBills", secondBills);
            resultMap.put("thirdBills", thirdBills);
            resultMap.put("depositMaterials", depositMaterials);
            return ResponseWrapper.builder().path(request.getServletPath()).data(resultMap)
                .status(HttpStatus.OK.value()).build();
        } catch (Exception e) {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return ResponseWrapper.builder().status(HttpStatus.INTERNAL_SERVER_ERROR.value()).message(e.getMessage())
                .path(request.getContextPath()).build();
        }
    }

    // 发送响应流方法
    private void setResponseHeader(HttpServletResponse response, String fileName) {
        try {
            try {
                fileName = new String(fileName.getBytes(), "ISO8859-1");
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            response.setContentType("application/octet-stream;charset=ISO8859-1");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.addHeader("Pargam", "no-cache");
            response.addHeader("Cache-Control", "no-cache");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
